#include "DeviceSampleHelper.h"

#include <QDebug>

#include "ConstNames.h"
#include "ModbusManager.h"

#define REG_SYSTEM_STATE 0x03         // 系统状态
#define REG_SYSTEM_ERROR 0x32         // 系统错误
#define REG_START_SAMPLING_PUMP 0x05  // 启动采样泵
#define REG_STOP_SAMPLING_PUMP 0x06   // 停止采样泵
#define REG_DRAIN_CONTROL 0x07        // 排空控制
#define REG_CURRENT_BOTTLE 0x30       // 当前瓶号
#define REG_READ_TIME_YEAR_MONTH 0x7  // 时钟：年(高8位)+月(低8位)
#define REG_READ_TIME_DAY_HOUR 0x8    // 时钟：日(高8位)+时(低8位)
#define REG_READ_TIME_MIN_SEC 0x9     // 时钟：分(高8位)+秒(低8位)
#define REG_TIME_YEAR_MONTH 0x88      // 时钟：年(高8位)+月(低8位)
#define REG_TIME_DAY_HOUR 0x89        // 时钟：日(高8位)+时(低8位)
#define REG_TIME_MIN_SEC 0x8A         // 时钟：分(高8位)+秒(低8位)

// 采样设备状态定义
typedef enum {
    STATE_IDLE = 0,                           // 0000：待机
    STATE_BOTTLE_RESET = 1,                   // 0001：瓶复位
    STATE_CONSTANT_FLOW_VOLUME_SAMPLING = 2,  // 0002：定流定量采样
    STATE_TIMED_PROPORTIONAL_SAMPLING = 3,    // 0003：定时比例采样
    STATE_TIMED_SAMPLING = 4,                 // 0004：定时采样
    STATE_VOLUME_SAMPLING = 5,                // 0005：定量采样
    STATE_BOTTLE_DRAIN = 7,                   // 0007：瓶排空
} sample_state_t;

typedef enum {
    CMD_START_PUMP = 1,  // 启动采样泵
    CMD_STOP_PUMP = 2,   // 停止采样泵
    CMD_DRAIN = 3,       // 排空所有瓶
    CMD_DRAIN_PRE = 4,   // 排空上一瓶
    CMD_SET_TIME = 5,    // 设置时间
} sample_cmd_t;

// 操作到寄存器地址的映射
static const QMap<quint16, quint16> SAMPLE_CMD_ADDR_MAP = {
    {CMD_START_PUMP, REG_START_SAMPLING_PUMP},
    {CMD_STOP_PUMP, REG_STOP_SAMPLING_PUMP},
    {CMD_DRAIN, REG_DRAIN_CONTROL},
    {CMD_DRAIN_PRE, REG_DRAIN_CONTROL},  // 排空上一瓶也使用同一寄存器
};

// 操作到控制值的映射
static const QMap<quint16, quint16> SAMPLE_CMD_VALUE_MAP = {
    {CMD_START_PUMP, 1}, {CMD_STOP_PUMP, 1}, {CMD_DRAIN, 0},  // 排空默认值为0（排空所有瓶）
};

static const QMap<QString, quint16> SAMPLE_OPERATE_MAP = {
    {OperationNames::SAMPLE_INTAKE, CMD_START_PUMP},
    {OperationNames::SAMPLE_INTAKE_STOP, CMD_STOP_PUMP},
    {OperationNames::SAMPLE_DRAIN, CMD_DRAIN},
    {OperationNames::SAMPLE_DRAIN_PRE, CMD_DRAIN_PRE},
    {OperationNames::COMMON_SET_TIME, CMD_SET_TIME},
};

static const QMap<quint16, QString> SAMPLE_STATE_MAP = {
    {STATE_IDLE, StateNames::SAMPLE_STATE_IDLE},
    {STATE_BOTTLE_RESET, StateNames::SAMPLE_STATE_BOTTLE_RESET},
    {STATE_CONSTANT_FLOW_VOLUME_SAMPLING, StateNames::SAMPLE_STATE_CONSTANT_FLOW_VOLUME},
    {STATE_TIMED_PROPORTIONAL_SAMPLING, StateNames::SAMPLE_STATE_TIMED_PROPORTIONAL},
    {STATE_TIMED_SAMPLING, StateNames::SAMPLE_STATE_TIMED_SAMPLING},
    {STATE_VOLUME_SAMPLING, StateNames::SAMPLE_STATE_VOLUME_SAMPLING},
    {STATE_BOTTLE_DRAIN, StateNames::SAMPLE_STATE_BOTTLE_DRAIN},
};

typedef enum {
    ERROR_NONE = 0x0000,                  // 无错误
    ERROR_THERMOMETER = 0x0001,           // 位0：温度计故障
    ERROR_FRIDGE_TEMP_OVER = 0x0002,      // 位1：冰箱温度超限
    ERROR_DISTRIBUTOR_ARM = 0x0004,       // 位2：分配臂故障
    ERROR_WATER_INSUFFICIENT = 0x0008,    // 位3：水量不足
    ERROR_REAGENT_INSUFFICIENT = 0x0010,  // 位4：药品不足
    ERROR_BOTTLE_FULL = 0x0020,           // 位5：瓶满
    ERROR_FRIDGE_AUTO_PROTECT = 0x0040,   // 位6：冰箱自动保护
    ERROR_LIFT_ROD = 0x0080,              // 位7：升降杆故障
    ERROR_BOTTLE_DISTRIBUTE = 0x0100,     // 位8：分瓶故障
} sample_error_type_t;

static const QMap<quint16, QString> SAMPLE_ERROR_TYPE_MAP = {
    {ERROR_NONE, ErrorNames::COMMON_ERROR_NONE},
    {ERROR_THERMOMETER, ErrorNames::SAMPLE_ERROR_THERMOMETER},
    {ERROR_FRIDGE_TEMP_OVER, ErrorNames::SAMPLE_ERROR_FRIDGE_TEMP_OVER},
    {ERROR_DISTRIBUTOR_ARM, ErrorNames::SAMPLE_ERROR_DISTRIBUTOR_ARM},
    {ERROR_WATER_INSUFFICIENT, ErrorNames::SAMPLE_ERROR_WATER_INSUFFICIENT},
    {ERROR_REAGENT_INSUFFICIENT, ErrorNames::SAMPLE_ERROR_REAGENT_INSUFFICIENT},
    {ERROR_BOTTLE_FULL, ErrorNames::SAMPLE_ERROR_BOTTLE_FULL},
    {ERROR_FRIDGE_AUTO_PROTECT, ErrorNames::SAMPLE_ERROR_FRIDGE_AUTO_PROTECT},
    {ERROR_LIFT_ROD, ErrorNames::SAMPLE_ERROR_LIFT_ROD},
    {ERROR_BOTTLE_DISTRIBUTE, ErrorNames::SAMPLE_ERROR_BOTTLE_DISTRIBUTE},
};

DeviceSampleHelper::DeviceSampleHelper(QString deviceName, QObject* parent)
    : IDevice(deviceName, parent)
{
    m_operateMap = SAMPLE_OPERATE_MAP;
    m_statusMap = SAMPLE_STATE_MAP;
    m_errorMap = SAMPLE_ERROR_TYPE_MAP;
    qDebug() << "initialized with device name:" << m_deviceName;
}

DeviceSampleHelper::~DeviceSampleHelper()
{
    qDebug() << "destroyed for device name:" << m_deviceName;
}

void DeviceSampleHelper::control(quint16 optCode)
{
    quint16 addr = SAMPLE_CMD_ADDR_MAP.value(optCode, 0);
    quint16 data = 0;
    if (optCode == CMD_DRAIN_PRE) {
        data = (m_current_bottle == 1) ? 12 : (m_current_bottle - 1);  // 1-12循环递减
    } else {
        data = SAMPLE_CMD_VALUE_MAP.value(optCode, 0);
    }
    IDevice::control(addr, data);
}

void DeviceSampleHelper::onGetDeviceData()
{
    if (m_busyFlags.dataBusy) {
        return;
    }
    m_busyFlags.dataBusy = true;

    ModbusHelper* modbus = ModbusManager::instance()->getModbusHelper(m_deviceName);
    if (!modbus) {
        qDebug() << "Failed to get ModbusHelper for device:" << m_deviceName;
        m_busyFlags.dataBusy = false;
        return;
    }
    modbus->asyncRead(REG_SYSTEM_STATE, 1)
        .then([this, modbus](const QVector<quint16>& result) {
            m_deviceData.status = result[0];
            m_isIdle = m_deviceData.status == STATE_IDLE;
            return modbus->asyncRead(REG_SYSTEM_ERROR, 1);
        })
        .then([this, modbus](const QVector<quint16>& result) {
            m_deviceData.faultCode = result[0];
            if (m_deviceData.faultCode != m_lastFaultCode && m_deviceData.faultCode != ERROR_NONE) {
                emit errorOccurred(QString("错误: %1").arg(getErrorName(m_deviceData.faultCode)));
            }
            m_lastFaultCode = m_deviceData.faultCode;
            return modbus->asyncRead(REG_CURRENT_BOTTLE, 1);  // 读取当前瓶号
        })
        .then([this, modbus](const QVector<quint16>& result) {
            m_current_bottle = result[0];
            return modbus->asyncRead(REG_READ_TIME_YEAR_MONTH, 3);  // 读取3个时间寄存器
        })
        .then([this](const QVector<quint16>& result) {
            // 解析时间数据
            quint16 yearMonth = result[0];
            quint16 dayHour = result[1];
            quint16 minSec = result[2];

            // BCD码转换
            int year = ((yearMonth >> 8) & 0xFF);  // 高8位：年
            int month = (yearMonth & 0xFF);        // 低8位：月
            int day = ((dayHour >> 8) & 0xFF);     // 高8位：日
            int hour = (dayHour & 0xFF);           // 低8位：时
            int minute = ((minSec >> 8) & 0xFF);   // 高8位：分
            int second = (minSec & 0xFF);          // 低8位：秒

            // 年份可能需要处理（如果是两位数年份，需要转换为四位数）
            if (year < 100) {
                year += 2000;  // 假设是21世纪
            }

            QDateTime datetime(QDate(year, month, day), QTime(hour, minute, second));
            m_deviceData.datetime = datetime;
            emit deviceDataChanged(m_deviceData);
        })
        .finally([this]() { m_busyFlags.dataBusy = false; });
}

void DeviceSampleHelper::setDeviceTime(const QDateTime& datetime)
{
    if (m_busyFlags.controlBusy) {
        return;
    }
    m_busyFlags.controlBusy = true;

    ModbusHelper* modbus = ModbusManager::instance()->getModbusHelper(m_deviceName);
    if (!modbus) {
        qDebug() << "Failed to get ModbusHelper for device:" << m_deviceName;
        m_busyFlags.controlBusy = false;
        return;
    }

    // 准备时间数据
    int year = datetime.date().year();
    int month = datetime.date().month();
    int day = datetime.date().day();
    int hour = datetime.time().hour();
    int minute = datetime.time().minute();
    int second = datetime.time().second();

    // 如果年份是四位数，转换为两位数（取后两位）
    if (year >= 2000) {
        year = year - 2000;
    }

    quint16 yearMonth = (year) << 8 | month;  // 年(高8位) + 月(低8位)
    quint16 dayHour = (day) << 8 | hour;      // 日(高8位) + 时(低8位)
    quint16 minSec = (minute) << 8 | second;  // 分(高8位) + 秒(低8位)

    QVector<quint16> data;
    data << yearMonth << dayHour << minSec;
    modbus->asyncWrite(REG_TIME_YEAR_MONTH, data)
        .fail([this](const QString& error) {
            qDebug() << "Failed to write time registers for device:" << m_deviceName
                     << "Error:" << error;
        })
        .finally([this]() { m_busyFlags.controlBusy = false; });
}